﻿namespace USSDRunner.ViewModels
{
    using System.Collections.ObjectModel;
    using System.Globalization;
    using System.IO;
    using System.IO.IsolatedStorage;
    using System.Linq;
    
    using Microsoft.Phone.Tasks;

    /// <summary>
    /// Represents USSD message view model.
    /// </summary>
    public class MessageViewModel : NotifyPropertyChangedBase
    {
        private const int MaxMessageLength = 182;

        private const string TitleKey = "Title";

        private const string ParametersCountKey = "ParametersCount";

        private string title;

        /// <summary>
        /// Gets a value indicating whether the data is loaded.
        /// </summary>
        /// <value>
        /// <c>true</c> if the data is loaded; otherwise, <c>false</c>.
        /// </value>
        public bool IsDataLoaded { get; private set; }

        /// <summary>
        /// Gets or sets the USSD message title.
        /// </summary>
        /// <value>
        /// The USSD message title.
        /// </value>
        public string Title
        {
            get
            {
                return title;
            }

            set
            {
                if (title != value)
                {
                    title = value;
                    OnPropertyChanged(TitleKey);

                    WriteToIsolatedStorage(TitleKey, Title);
                }
            }
        }

        /// <summary>
        /// Gets the USSD message body (main part of the USSD message without parameters).
        /// </summary>
        public MessageBodyViewModel Body { get; private set; }

        /// <summary>
        /// Gets a collection for ItemViewModel objects.
        /// </summary>
        public ObservableCollection<MessageParameterViewModel> Parameters { get; private set; }

        /// <summary>
        /// Gets a value indicating whether it is possible to add a parameter to USSD message.
        /// </summary>
        /// <value>
        /// <c>true</c> if it is possible to add a parameter to USSD message; otherwise, <c>false</c>.
        /// </value>
        public bool CanAddParameter
        {
            get
            {
                return !string.IsNullOrEmpty(FullMessage) && FullMessage.Length < MaxMessageLength;
            }
        }

        /// <summary>
        /// Gets a value indicating whether it is possible to remove last USSD message parameter.
        /// </summary>
        /// <value>
        /// <c>true</c> if it is possible to remove last USSD message parameter; otherwise, <c>false</c>.
        /// </value>
        public bool CanRemoveLastParameter
        {
            get
            {
                return Parameters.Any();
            }
        }

        /// <summary>
        /// Gets the full USSD message.
        /// </summary>
        public string FullMessage 
        {
            get
            {
                if (!Body.IsValid || !Parameters.All(p => p.IsValid))
                {
                    return null;
                }

                string fullMessage;
                if (Parameters.Count == 0)
                {
                    fullMessage = Body.Text;
                }
                else 
                {
                    string parameters = string.Join(MessageItemViewModelBase.Asterisk.ToString(CultureInfo.InvariantCulture), Parameters.Select(p => p.Text).ToArray());
                    parameters = string.Concat(MessageItemViewModelBase.Asterisk.ToString(CultureInfo.InvariantCulture), parameters);
                    fullMessage = Body.Text.Insert(Body.Text.Length - 1, parameters);
                }

                return fullMessage;
            }
        }

        /// <summary>
        /// Reads the value from isolated storage.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <returns>The stored value.</returns>
        public static string ReadFromIsolatedStorage(string key)
        {
            using (var isolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication())
            {
                using (var streamReader = new StreamReader(isolatedStorageFile.OpenFile(key, FileMode.OpenOrCreate, FileAccess.Read)))
                {
                    return streamReader.ReadToEnd();
                }
            }
        }

        /// <summary>
        /// Writes the value to isolated storage.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="value">The stored value.</param>
        public static void WriteToIsolatedStorage(string key, string value)
        {
            using (var isolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication())
            {
                using (var streamWriter = new StreamWriter(isolatedStorageFile.OpenFile(key, FileMode.Create, FileAccess.Write)))
                {
                    streamWriter.Write(value);
                }
            }
        }

        /// <summary>
        /// Adds the parameter to the USSD message.
        /// </summary>
        public void AddParameter()
        {
            var newParameter = new MessageParameterViewModel(Parameters.Count);
            newParameter.PropertyChanged += HandleMessageChanged;
            Parameters.Add(newParameter);
            OnCanAddParameterChanged();
            OnCanRemoveLastParameterChanged();

            WriteParametersCountToIsolatedStorage();
        }

        /// <summary>
        /// Removes the last parameter of the USSD message.
        /// </summary>
        public void RemoveLastParameter()
        {
            var lastParameter = Parameters.Last();
            lastParameter.PropertyChanged -= HandleMessageChanged;

            Parameters.Remove(lastParameter);
            OnFullMessageChanged();
            OnCanAddParameterChanged();
            OnCanRemoveLastParameterChanged();

            WriteParametersCountToIsolatedStorage();
        }

        /// <summary>
        /// Sends the USSD message.
        /// </summary>
        public void SendMessage()
        {
            var task = new PhoneCallTask
                {
                    PhoneNumber = FullMessage, 
                    DisplayName = Title
                };
            task.Show();
        }

        /// <summary>
        /// Clears the message.
        /// </summary>
        public void ClearMessage()
        {
            Title = string.Empty;
            Body.Text = string.Empty;
            Parameters.Clear();
            
            WriteParametersCountToIsolatedStorage();
        }

        /// <summary>
        /// Initializes this instance.
        /// </summary>
        public void Initialize()
        {
            Title = string.Empty;

            Body = new MessageBodyViewModel();
            Body.PropertyChanged += HandleMessageChanged;
            Body.Text = string.Empty;

            Parameters = new ObservableCollection<MessageParameterViewModel>();
            WriteParametersCountToIsolatedStorage();

            IsDataLoaded = true;
        }

        /// <summary>
        /// Loads the data.
        /// </summary>
        public void LoadData()
        {
            Title = ReadFromIsolatedStorage(TitleKey);

            Body = new MessageBodyViewModel();
            Body.PropertyChanged += HandleMessageChanged;
            Body.LoadTextFromIsolatedStorage();
            var parametersCountString = ReadFromIsolatedStorage(ParametersCountKey);
            var parametersCount = int.Parse(parametersCountString, CultureInfo.InvariantCulture);

            Parameters = new ObservableCollection<MessageParameterViewModel>();
            for (int parametersIndex = 0; parametersIndex < parametersCount; parametersIndex++)
            {
                AddParameter();
                var currentParameter = Parameters[parametersIndex];
                currentParameter.LoadTextFromIsolatedStorage();
            }

            IsDataLoaded = true;
        }

        private void WriteParametersCountToIsolatedStorage()
        {
            WriteToIsolatedStorage(ParametersCountKey, this.Parameters.Count.ToString(CultureInfo.InvariantCulture));
        }

        private void HandleMessageChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            OnFullMessageChanged();
            OnCanAddParameterChanged();
        }

        private void OnFullMessageChanged()
        {
            OnPropertyChanged("FullMessage");
        }

        private void OnCanAddParameterChanged()
        {
            OnPropertyChanged("CanAddParameter");
        }

        private void OnCanRemoveLastParameterChanged()
        {
            OnPropertyChanged("CanRemoveLastParameter");
        }
    }
}